﻿Imports System.Text
Imports Microsoft.VisualStudio.Text.Editor
Imports System.ComponentModel.Composition
Imports Microsoft.VisualStudio.Utilities
Imports TwitterAPI
Imports System.Timers
Imports System.Windows.Controls
Imports System.Windows
Imports VsSpeakerCompanion.UI

Namespace VsSpeakerCompanion
	Friend Class WidgetManager
		Implements IVisualStudioService
        Private WithEvents context As Context
        Private WithEvents timer As Timer
        Private mTwitterService As TwitterService
        Private views As List(Of IWpfTextView)
        Private sidebarPresenter As SidebarPresenter
        Private mUIService As IUIService

        Private _serviceProvider As IServiceProvider

        Private Shared managerInstance As WidgetManager

        Private Sub New()
            Me.context = New Context
            Me.views = New List(Of IWpfTextView)
            Me.mTwitterService = New TwitterService
            Me.timer = New Timer(3000)
            Me.mUIService = New UIService(Me)
        End Sub

        Friend Shared ReadOnly Property Instance As WidgetManager
            Get
                If managerInstance Is Nothing Then
                    managerInstance = New WidgetManager
                End If

                Return managerInstance
            End Get
        End Property

        Friend Sub Add(ByVal view As IWpfTextView)
            Me.views.Add(view)
            AddWidgetsToTheView(view)
            SubscribeToViewEvents(view)
        End Sub

        Private Sub SubscribeToViewEvents(ByVal view As IWpfTextView)
            AddHandler view.VisualElement.IsVisibleChanged, AddressOf OnViewVisualElementIsVisibleChanged
            AddHandler view.VisualElement.SizeChanged, AddressOf OnViewVisualElementSizeChanged
            AddHandler view.ViewportLeftChanged, AddressOf OnViewViewportLeftChanged
            AddHandler view.Closed, AddressOf OnViewClosed
        End Sub

        Private Sub UnsubscribeFromViewEvents(ByVal view As IWpfTextView)
            RemoveHandler view.VisualElement.IsVisibleChanged, AddressOf OnViewVisualElementIsVisibleChanged
            RemoveHandler view.VisualElement.SizeChanged, AddressOf OnViewVisualElementSizeChanged
            RemoveHandler view.ViewportLeftChanged, AddressOf OnViewViewportLeftChanged
            RemoveHandler view.Closed, AddressOf OnViewClosed
        End Sub

        Private Sub OnViewViewportLeftChanged(ByVal sender As Object, ByVal e As EventArgs)
            Dim view = TryCast(sender, IWpfTextView)
            Me.sidebarPresenter.Dock(view)
        End Sub

        Private Sub OnViewVisualElementIsVisibleChanged(ByVal sender As Object, ByVal e As DependencyPropertyChangedEventArgs)
            If CBool(e.NewValue) = True Then
                Dim targetView = Me.views.FirstOrDefault(Function(view) view.VisualElement Is sender)

                If targetView IsNot Nothing Then
                    AddWidgetsToTheView(targetView)
                End If
            End If
        End Sub

        Private Sub OnViewVisualElementSizeChanged(ByVal sender As Object, ByVal e As SizeChangedEventArgs)
            Dim targetView = Me.views.FirstOrDefault(Function(view) view.VisualElement Is sender)

            If targetView IsNot Nothing Then
                Me.sidebarPresenter.Dock(targetView)
            End If
        End Sub

        Friend Property IsInitialized As Boolean

        Friend Sub Initialize(ByVal providers As IEnumerable(Of IWidgetProvider))
            If Not IsInitialized Then
                Me.context.Settings.Load()

                Me.sidebarPresenter = New SidebarPresenter(Me, Me.context, Me.mUIService)

                ' Initialize widgets
                For Each provider As IWidgetProvider In providers
                    For Each widget As IWidget In provider.GetWidgets(context)
                        sidebarPresenter.Add(widget)
                    Next widget
                Next provider

                IsInitialized = True
            End If
        End Sub

        Private Sub OnContextSessionStarting() Handles context.SessionStarting
            Me.mTwitterService.Reset()
            Me.sidebarPresenter.Reset()
            Me.timer.Start()
        End Sub

        Private Sub OnContextSessionEnding() Handles context.SessionEnding
            Me.timer.Stop()
        End Sub

        Private Sub OnContextSessionStarted() Handles context.SessionStarted
            Me.context.Settings.Save()
        End Sub

        Private Sub OnContextSessionEnded() Handles context.SessionEnded
            Me.context.Settings.Save()
        End Sub

        Private Sub OnViewClosed(ByVal sender As Object, ByVal e As EventArgs)
            Dim view = TryCast(sender, IWpfTextView)
            RemoveWidgetsFromTheView(view)
            UnsubscribeFromViewEvents(view)
            Me.views.Remove(view)
        End Sub

        Private Sub AddWidgetsToTheView(ByVal view As IWpfTextView)
            Dim previousViewWithWidgets = GetActiveTextView()

            If previousViewWithWidgets IsNot Nothing Then
                RemoveWidgetsFromTheView(previousViewWithWidgets)
            End If

            view.Properties.AddProperty(GetType(WidgetManager), Me)
            Me.sidebarPresenter.Dock(view)

            Dim layer = GetAdornmentLayer(view)
            layer.AddAdornment(AdornmentPositioningBehavior.ViewportRelative, Nothing, Me, Me.sidebarPresenter.VisualElement, Nothing)
        End Sub

        Private Function GetAdornmentLayer(ByVal view As IWpfTextView) As IAdornmentLayer
            Return view.GetAdornmentLayer("VS Speaker Adornments Layer")
        End Function

        Private Sub RemoveWidgetsFromTheView(ByVal view As IWpfTextView)
            If view IsNot Nothing Then
                view.Properties.RemoveProperty(GetType(WidgetManager))
                Dim adornmentLayer = GetAdornmentLayer(view)
                adornmentLayer.RemoveAdornmentsByTag(Me)
            End If
        End Sub

        Private Sub TimerElapsed() Handles timer.Elapsed
            Try
                mTwitterService.ProcessMessages(Sub(ex) Logger.Log(ex))
            Catch ex As Exception
                Logger.Log(ex)
            End Try
        End Sub

        Public Function GetActiveTextView() As IWpfTextView Implements IVisualStudioService.GetActiveTextView
            Return Me.views.FirstOrDefault(Function(view) view.Properties.ContainsProperty(GetType(WidgetManager)))
        End Function

        Public ReadOnly Property IVisualStudioService_ServiceProvider As System.IServiceProvider Implements IVisualStudioService.ServiceProvider
            Get
                Return Me.ServiceProvider
            End Get
        End Property

        Public Property ServiceProvider As IServiceProvider
            Get
                Return Me._serviceProvider
            End Get
            Set(ByVal value As IServiceProvider)
                Me._serviceProvider = value
            End Set
        End Property

        Friend ReadOnly Property TwitterService As TwitterService
            Get
                Return Me.mTwitterService
            End Get
        End Property

        Friend ReadOnly Property UIService As IUIService
            Get
                Return Me.mUIService
            End Get
        End Property
	End Class
End Namespace